package com.ytf.dogbox.inteflyCamera;

import android.content.Context;
import android.os.Environment;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.TextureView;

import com.ytf.dogbox.activity.FlyUtil;
import com.ytf.dogbox.util.HttpUtil;
import com.ytf.dogbox.util.Log;
import com.ytf.dogbox.util.TestConfig;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentLinkedDeque;

import intefly.tiwolf.mqttcamera.inteflyCamera.InteflyOpenGLView;
import intefly.tiwolf.mqttcamera.maiteCamera.AACproduct;
import intefly.tiwolf.mqttcamera.maiteCamera.DumAACProduct;
import intefly.tiwolf.mqttcamera.maiteCamera.MaiteOpenGLView;

/**
 * @author tiwolf_li
 * @Date on 2021/6/18
 * @Description
 */
public class InteflyCameraView extends TextureView implements AACproduct.IshowPcm, InteflyOpenGLView.IGedDataFromNativeListener{

    private String TAG=InteflyCameraView.class.getSimpleName();

    //解码器
    private MediaCodecUtil codecUtil;

    private MediaCodecBitmapUtil bitmapCodecUtil;
    //读取文件解码线程
    private MediaCodecThread thread;

    private MediaCodecBitmapThread bitmapThread;

    private SurfaceHolder holder;

    Context context;


    static int handle=-1;
    static int handle1=-1;

    static int isStopInt=1;
    private boolean isOne=true;

    private int isItfRtmpInitFlag=-1;

    private int playBackHandler;

    private InteflyOpenGLView inteflyOpenGLView;

    public InteflyCameraView(Context context) {
        super(context);
        this.context=context;
    }

    public InteflyCameraView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        this.context=context;
        init();
    }

    private void init() {

        inteflyOpenGLView=new InteflyOpenGLView(this);

        Log.i("tiwolf", "init初始化通道得到: "+inteflyOpenGLView );

    }

    public void initAudio(){
        aaCproduct=new AACproduct(this);
        aaCproduct.start();
    }

    //打开虚拟的音频
    public void initDumAudio(){
        dumAACProduct=new DumAACProduct(this);
        dumAACProduct.start();
    }

    //关闭虚拟音频
    public void closeDumAudio(){
        if (dumAACProduct!=null){
            dumAACProduct.closeDum();
            dumAACProduct=null;
        }
    }

    public void setBitmapCodecUtil(){
        Log.i(TAG, "surfaceCreated: 初始化bitmapCodecUtil init" );
        if (bitmapCodecUtil==null){
            bitmapCodecUtil=new MediaCodecBitmapUtil(null,camerawidth,cameraheight);
            bitmapCodecUtil.setiByteArray(new MediaCodecBitmapUtil.IByteArray() {
                @Override
                public void setByteArray(byte[] nv21,int width1,int height1) {
                    Log.i(TAG, "setByteArray: 解码-流 nv21帧图片" );
                    if (nv21!=null){
                        width=width1;
                        height=height1;
                        iShowPicture.showData(nv21,height,width);
                    }

                }

                @Override
                public void setyuvArray(byte[] yuv,int width,int height) {
                    Log.i(TAG, "setByteArray: 解码-流 yuv帧图片" );

                }
            });
            bitmapCodecUtil.startCodec();
        }
    }



    private boolean isMethod2Flag=true;
    public synchronized void startGetH264(String url){
        if (isMethod2Flag){
            boolean ping = HttpUtil.ping("192.168.110.123");
            Log.i(TAG, "run: 开始获取h264流===="+ping+";url="+url );
            if (ping){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        isMethod2Flag=false;
                        Log.i(TAG, "run: 开始获取h264流8888" );
                        inteflyOpenGLView.callMethod2(url);
                        isMethod2Flag=true;
                        Log.i(TAG, "startGetH264:这个已经码流结束了===========" );
                    }
                }).start();
            }
        }
    }

    String usrname="admin";
    String pwd="YWRtaW4=";
    String ip ="192.168.110.123";
    int i=2;
    //这个是是否连接摄像头标志
    public static boolean inteflyRtmpFlag=false;
    //initPublisher方法是否已经跑完
    private boolean isPublisherFinish=true;

    private int camerawidth=640;
    private int cameraheight=480;
    public void setBitmapSize(int width,int height){
        this.camerawidth=width;
        this.cameraheight=height;
    }

    public void setCameraSize(int width,int height){
        if (bitmapThread!=null){
            bitmapThread.setMaxFrameNum(20);
        }

        Log.i(TAG, "OnDataCallBack: 解码-流开始 宽="+width+";高="+height);

        if (bitmapCodecUtil!=null){
            bitmapCodecUtil.setCodecSize(width,height);
        }

    }

    /**
     * 初始化推流器 如果没有连接上，在有网的情况下重连5次
     */
    public void initPublisher(){
        isItfRtmpInitFlag= MaiteOpenGLView.StartRTMPStream(1,"maite", TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01");
        Log.i(TAG, "initPublisher: 初始化摄像头RTMP得到的返回值是-----"+isItfRtmpInitFlag);
        if (isItfRtmpInitFlag==1){
            MaiteOpenGLView.StopRTMPStream(0,TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01");
            MaiteOpenGLView.StopRTMPStream(isItfRtmpInitFlag,TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01");
            initPublisher();
        }else if (isItfRtmpInitFlag>=0){
            int liveInt = MaiteOpenGLView.StartLiveStream(isItfRtmpInitFlag, TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01");
            Log.i(TAG, "initPublisher: 摄像头推流设置返回值为"+liveInt);
            if (liveInt==0){
                inteflyRtmpFlag=true;
            }else if (liveInt!=0 && ishasNetWork){
                boolean flag=false;
                Log.i(TAG, "initPublisher: 开始循环---摄像头推流");
                for (int j = 0; j < 5; j++) {
                    int liveInt1 = MaiteOpenGLView.StartLiveStream(isItfRtmpInitFlag, TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01");
                    Log.i(TAG, "initPublisher: 循环内---摄像头推流设置返回值为"+liveInt1);
                    if (liveInt1==0){
                        flag=true;
                        Log.i(TAG, "initPublisher: 循环内---摄像头推流成功33333");
                        break;
                    }
                    Log.i(TAG, "initPublisher: 循环内---摄像头上一次推流未成功11111111");
                }
                Log.i(TAG, "initPublisher: 结束循环---摄像头推流");
                if (flag){
                    inteflyRtmpFlag=true;
                }else {
                    inteflyRtmpFlag=false;
                }

            }else {
                inteflyRtmpFlag=false;
            }
        }

    }

    private boolean ishasNetWork=false;
    private int conTime=0;
    public void getNetWork(boolean isHasNetWork){
        this.ishasNetWork=isHasNetWork;
    }


    /**
     * 停止推流，出现网络动荡的情况下
     */
    public void stopRtmpPublish(){
//        isItfRtmpInitFlag=-1;//恢复到初始情况，然后再重新连接流媒体服务器，重新开始推流
        inteflyRtmpFlag=false;
        if(isItfRtmpInitFlag>=0){
            int liveStop = MaiteOpenGLView.StopLiveStream(isItfRtmpInitFlag, TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01");
            Log.i(TAG, "stopRtmpPublish: 停止摄像头得到"+liveStop );
        }
    }

    private void stopDecodec(){
        if (bitmapCodecUtil!=null){
            bitmapCodecUtil.stopCodec();
            bitmapCodecUtil=null;
        }

        if (bitmapThread!=null && bitmapThread.isAlive()){
            bitmapThread.stopThread();
            bitmapThread=null;
        }
    }

    public void destroy(){
        cacheLinkedDeque.clear();

        isSendFlag=false;
        if (picWorker != null) {
            picWorker.interrupt();
            try {
                picWorker.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
                picWorker.interrupt();
            }
            picWorker = null;
        }

        if (isItfRtmpInitFlag>=0){
            int intStop = MaiteOpenGLView.StopRTMPStream(isItfRtmpInitFlag, TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01");
            Log.i(TAG, "stopRtmpPublish: 停止编译，释放资源"+intStop );
        }
        if (aaCproduct!=null){
            aaCproduct.stopRecordFlag();
        }
        try {
            Thread.sleep(120);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (dumAACProduct!=null){
            dumAACProduct.closeDum();
        }

        stopDecodec();

    }

    public void stopRecord(){
        aaCproduct.stopAudioRecord();
    }

    boolean stopRtmpFlag=false;
    public synchronized void startRtmpPublisher(boolean stopRtmpFlag){
        this.stopRtmpFlag=stopRtmpFlag;
        Log.i(TAG, "startRtmpPublisher: 将摄像头推流指令结果为--"+inteflyRtmpFlag );
        if (isPublisherFinish){
            isPublisherFinish=false;

            if(!inteflyRtmpFlag){
                Log.i(TAG, "receiveWork: 摄像头重新初始化推流设置" );
                initPublisher();
            }
            isPublisherFinish=true;
        }


    }

    public void stopRtmpPublisher(){
        MaiteOpenGLView.StopLiveStream(isItfRtmpInitFlag,TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01");
        inteflyRtmpFlag=false;
    }


    /**
     * 初始化推流器 如果没有连接上，在有网的情况下重连5次
     */
    public void initPublisher(String url){
        isItfRtmpInitFlag= MaiteOpenGLView.StartRTMPStream(1,"maite", url);
        Log.i(TAG, "initPublisher: 七牛云初始化摄像头RTMP得到的返回值是-----"+isItfRtmpInitFlag);
        if (isItfRtmpInitFlag==1){
            MaiteOpenGLView.StopRTMPStream(0,url);
            MaiteOpenGLView.StopRTMPStream(isItfRtmpInitFlag,url);
            initPublisher(url);
        }else if (isItfRtmpInitFlag>=0){
            int liveInt = MaiteOpenGLView.StartLiveStream(isItfRtmpInitFlag, url);
            Log.i(TAG, "initPublisher: 七牛云摄像头推流设置返回值为"+liveInt);
            if (liveInt==0){
                inteflyRtmpFlag=true;
            }else if (liveInt!=0 && ishasNetWork){
                boolean flag=false;
                Log.i(TAG, "initPublisher: 七牛云开始循环---摄像头推流");
                for (int j = 0; j < 5; j++) {
                    int liveInt1 = MaiteOpenGLView.StartLiveStream(isItfRtmpInitFlag, url);
                    if (liveInt1==0){
                        flag=true;
                        Log.i(TAG, "initPublisher: 七牛云循环内---摄像头推流成功33333");
                        break;
                    }
                    Log.i(TAG, "initPublisher: 七牛云循环内---摄像头上一次推流未成功11111111");
                }
                if (flag){
                    inteflyRtmpFlag=true;
                }else {
                    inteflyRtmpFlag=false;
                }

            }else {
                inteflyRtmpFlag=false;
            }
        }

    }
    public synchronized void startRtmpPublisher(boolean stopRtmpFlag,String url){
        this.stopRtmpFlag=stopRtmpFlag;
        Log.i(TAG, "startRtmpPublisher: 七牛云将摄像头推流指令结果为--"+inteflyRtmpFlag );
        if (isPublisherFinish){
            isPublisherFinish=false;

            if(!inteflyRtmpFlag){
                Log.i(TAG, "receiveWork: 七牛云摄像头重新初始化推流设置" );
                initPublisher(url);
            }
            isPublisherFinish=true;
        }


    }

    public void stopRtmpPublisher(String url){
        MaiteOpenGLView.StopLiveStream(isItfRtmpInitFlag,url);
        inteflyRtmpFlag=false;
    }

    boolean isFirstRecordFlag=true;
    /**
     * 开始录制
     * @param path
     */
    public void startRecord(String path,String url){

        int recordInt=0;
        //石工的mp4录制
        if (isItfRtmpInitFlag>=0){
            recordInt = MaiteOpenGLView.StartRecord(isItfRtmpInitFlag, path);
        }else {
            //如果是小于0，则为初始化失败
            Log.i(TAG, "startRecord: 没有初始化导致摄像头在录制启动rtmp");
            if (url!=null){
                isItfRtmpInitFlag=MaiteOpenGLView.StartRTMPStream(1,"maite",url);
                //TODO 如果不添加这个，会导致设备一上来就向流媒体服务器推流
                if (isFirstRecordFlag){
                    isFirstRecordFlag=false;
                    MaiteOpenGLView.StopLiveStream(isItfRtmpInitFlag,url);
                }
            }

            //todo 如果使用isItfRtmpInitFlag这个标志，当我们为了可以录制录像将其设置成0的时候。在OnDataCallBack返回帧数据中，
            // 也是用isItfRtmpInitFlag这个来判断是否上传数据的，如果重启的时候没有网络，将isItfRtmpInitFlag设置为0的时候，
            // MaiteOpenGLView.SendVideoFrame_WithDelimiter(isItfRtmpInitFlag,len,data, ts);这个方法就会用起来，
            // 如此就是推流未打通的时候就往里面送数据，这样子就导致了内存不断的升高
//            if(isItfRtmpInitFlag<0){
//                isItfRtmpInitFlag=0;
//            }
//            recordInt = MaiteOpenGLView.StartRecord(isItfRtmpInitFlag, path);

            if(isItfRtmpInitFlag<0){
                recordInt=-1;
            }else{
//                recordInitFlag=isItfRtmpInitFlag;
                recordInt = MaiteOpenGLView.StartRecord(isItfRtmpInitFlag, path);
            }

        }
        if (recordInt==0){
            recordFlag=true;
        }
        Log.i(TAG, "startRecord: 录制获取到的返回值"+recordInt);
    }

    private AACproduct aaCproduct;
    private DumAACProduct dumAACProduct;

    public  boolean recordFlag=false;
    /**
     * 开始录制
     * @param path
     */
    public void startRecord(String path){

        int recordInt=0;
        //石工的mp4录制
        if (isItfRtmpInitFlag>=0){
            recordInt = MaiteOpenGLView.StartRecord(isItfRtmpInitFlag, path);
        }else {
            //如果是小于0，则为初始化失败
            isItfRtmpInitFlag=MaiteOpenGLView.StartRTMPStream(1,"maite", TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01");
            recordInt = MaiteOpenGLView.StartRecord(isItfRtmpInitFlag, path);
        }
        if (recordInt==0){
            recordFlag=true;
        }
        Log.i(TAG, "startRecord: 录制获取到的返回值"+recordInt);
    }

    public void endRecord(){


        if(isItfRtmpInitFlag>=0){
            //石工的停止录制
            MaiteOpenGLView.StopRecord(isItfRtmpInitFlag);
        }
        recordFlag=false;
    }

    public static void openLog(String filePath){
        new Thread(new Runnable() {
            @Override
            public void run() {
                MaiteOpenGLView.OpenPlayingLog(filePath);
            }
        }).start();
    }

    public static void closeLog(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                MaiteOpenGLView.ClosePlayingLog();
            }
        }).start();
    }

    public static void startHistory(String from, String to){
        new Thread(new Runnable() {
            @Override
            public void run() {
                handle = MaiteOpenGLView.StartPlayback(from, to);
                Log.i("onClick", "handle的值为 "+handle );
            }
        }).start();
    }


    private static int stopFlag=0;
    public static void stopHistory(String to){
        new Thread(new Runnable() {
            @Override
            public void run() {
                stopFlag= MaiteOpenGLView.StopPlayback(handle,to);
                // StopPlayback(handle,to);
            }
        }).start();
    }

    public static int isStopHistory(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (0==stopFlag){
                    isStopInt = MaiteOpenGLView.IsStop(handle);
                    Log.i("xiao", "run: 是否停止标志"+isStopInt);
                    stopFlag=isStopInt;
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        }).start();
        return isStopInt;
    }

    public int setThirdStreamParam(int code, String user, String passwd, String ip) {
        return inteflyOpenGLView.SetThirdStreamParam(code,user,passwd,ip);
    }

    public int getThirdStreamParam(int code, String user, String passwd, String ip) {
        return inteflyOpenGLView.GetThirdStreamParam(code,user,passwd,ip);
    }
    public int rebootCamera(int code,String user,String passwd,String ip){
        return inteflyOpenGLView.Reboot(code, user, passwd, ip);
    }
    public void stopStream(){
        inteflyOpenGLView.StopStream();
    }

    public void setStartStream(){
        inteflyOpenGLView.StartStream();
    }

    public int PrePoint(int code, String user, String passwd, String ip){
        return InteflyOpenGLView.PrePoint(code,user,passwd,ip);
    }

    public int login(int x, String user, String passwd, String ip){
        return InteflyOpenGLView.login(x, user, passwd, ip);
    }

    public int ptzRight(int itfi, String usrname, String pwd, String ip){
        return InteflyOpenGLView.PtzRight(itfi, usrname, pwd, ip);
    }

    public int ptzLeft(int itfi, String usrname, String pwd, String ip){
        return InteflyOpenGLView.PtzLeft(itfi, usrname, pwd, ip);
    }

    public int ptzStop(int itfi, String usrname, String pwd, String ip){
        return InteflyOpenGLView.PtzStop(itfi, usrname, pwd, ip);
    }

    public int ptzUp(int itfi, String usrname,String pwd,String ip){
        return InteflyOpenGLView.PtzUp(itfi, usrname, pwd, ip);
    }

    public int ptzDown(int itfi, String usrname,String pwd,String ip){
        return InteflyOpenGLView.PtzDown(itfi, usrname, pwd, ip);
    }

    public int zoomOut(int itfi, String usrname,String pwd,String ip){
        return InteflyOpenGLView.ZoomOut(itfi, usrname, pwd, ip);
    }

    public int zoomIn(int itfi, String usrname,String pwd,String ip){
        return InteflyOpenGLView.ZoomIn(itfi, usrname, pwd, ip);
    }

    boolean onedo=true;
    /**
     * 硬解码后的图像数据回调，需要注意，调用PlayVideo的第一个参数必须为OpenGLView对象，否则会没回调
     * 此格式在当前3188上返回的数据是NV12，如果需要NV21可以自行转换，或调用
     * 可以调用 RtspClass.NV21ToNV12(nv21, nv12, width, height, onlyUV); 进行转换或自行转换
     * @param yuv yuv420p数据
     * @param w NV21图像的宽
     * @param h NV21图像的高
     * @param format NV21的图像数据格式  ffmpeg里面格式为24
     * @param linesize 图像每行的占用数字，一般等于宽，不用处理
     * @return 应返回0
     */
    public int OnRecvYuvByte(byte[] yuv,int w, int h,int format,int linesize) {
        int result = w + h;
        Log.i("tiwolf", "maite yuv420P宽" + w+";高" + h+";格式-"+format+";行宽-"+linesize);

        return result;
    }

    byte[] bytes=null;
    byte[] bitmapBytes=null;
    int length=0;
    /**
     * H264数据流回调
     * 注意，不能在此回调函数中调用耗时的操作，否则会影响收流
     * @param nType 数据类型，0表示视频，1表示音频，2表示媒体参数
     * @param data 字节流
     * @param len 字节流长度
     * @param ts 时间截
     * @param iskey 是否关键帧  0非关键帧 1关键帧
     * @return 返回0
     */
    int sum=0;
    public int OnDataCallBack( int nType, byte[] data, int len, long ts, int iskey)
    {
        //初始化解码器
//        Log.i("tiwolf", "h264流返回:标志"+isItfRtmpInitFlag+" 类型-"+nType+"；字节流长度-"+len+";时间戳-"+ts+";关键帧-"+iskey );

        initCodec();
        //出现字节流长度和时间戳都为0的情况，这种情况直接跳过不管
        if (ts!=0 && len!=0){


            if (data!=null && data.length>0){
                iShowPicture.cameraIsWorking();
//                Log.e(TAG, "OnDataCallBack: isItfRtmpInitFlag="+isItfRtmpInitFlag+";nType="+nType+";ts="+ts );
                if (isItfRtmpInitFlag>=0 && nType==0 && ts!=0){
//                    Log.i(TAG, "OnDataCallBack: 11帧数据拿到数据并且上传"+thread+";=="+bitmapThread+";frameSendList="+frameSendList.size() );
                    if (bitmapThread!=null){
                        //arraycopy为浅复制，后面如果设置其中一个为null，则会影响到其他一个处理结果
                        byte[] bytes=new byte[len];
                        System.arraycopy(data,0,bytes,0,len);
                        bitmapThread.addH264(bytes);
                    }



                    MaiteOpenGLView.SendVideoFrame_WithDelimiter(isItfRtmpInitFlag,len,data, ts);

                }else{
//                    Log.i(TAG, "OnDataCallBack: 帧数据拿到数据不进行上传=============" );
                    if (bitmapThread!=null){
                        bitmapThread.addH264(data);
                    }

                }

            }
        }
//        Log.i(TAG, "OnDataCallBack: h264流上传rtmp,解码所花费的时间为="+(System.currentTimeMillis()-start) );



        return 0;
    }

    @Override
    public int HaiKangOnDataCallBack(int nType, byte[] data, int len, long ts, int iskey) {
        return 0;
    }

    @Override
    public int HaiKangOnDataCallBack1(int nType, byte[] data, int len, long ts, int iskey) {
        return 0;
    }

    @Override
    public int YuShiOnDataCallBack1(int nType, byte[] data, int len, long ts, int iskey) {
        return 0;
    }

    boolean isSendFlag=true;
    private ArrayList<StreamBean> frameSendList=new ArrayList<>();
    private Runnable SendFrameRunnable=new Runnable() {
        @Override
        public void run() {
            long startTime=0;
            Log.i(TAG, "run: 进行frameSendList 处理7777-----------"+isSendFlag+";"+frameSendList.size() );
            while (isSendFlag || frameSendList.size()>0){
                startTime=System.currentTimeMillis();
//                Log.i(TAG, "run: 进行frameSendList 开始处理-----------" );
                if (frameSendList.size()>0 &&  frameSendList.get(0)!=null && frameSendList.get(0).getData()!=null && frameSendList.get(0).getData().length>0){
                    boolean frameRtmpFlag=MaiteOpenGLView.SendVideoFrame_WithDelimiter(frameSendList.get(0).getIsItfRtmpInitFlag(),frameSendList.get(0).getLen(),frameSendList.get(0).getData(), frameSendList.get(0).getTs());
                    frameSendList.remove(0);
//                    Log.i(TAG, "run: 进行frameSendList 结束处理-----------++++++++++++++" );
                }else if (frameSendList.size()>0){
                    frameSendList.remove(0);
//                    Log.i(TAG, "run: 进行frameSendList 结束处理111111111111-----------++++++++++++++" );
                }

                sleepThread(startTime,System.currentTimeMillis());
            }


        }
    } ;

    //修眠
    private void sleepThread(long startTime, long endTime) {
        //根据读文件和解码耗时，计算需要休眠的时间
        long time = 40 - (endTime - startTime);
//        Log.i("tiwolf", "sleepThread: 解码-流 进行一次上传h264所需的时间为="+(endTime-startTime) );
        if (time > 0) {
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private synchronized void initCodec(){
        if (onedo){
            //有h264数据过来，马上开始准备解码，只启动一次
            onedo=false;
            bitmapThread=new MediaCodecBitmapThread(bitmapCodecUtil);
            bitmapThread.start();
            Log.i(TAG, "OnDataCallBack: 解码-流启动了一次，解码-流 宽="+width+";高="+height);
        }else if(bitmapThread==null){
            bitmapThread=new MediaCodecBitmapThread(bitmapCodecUtil);
            bitmapThread.start();
        }
    }

    /**
     * RGBA图像数据流回调
     * 注意，不能在此回调函数中调用耗时的操作，否则会影响收流
     * @param var1 字节流
     * @param var2 数据格式宽
     * @param var3 数据格式高
     * @param var4 format的RGBA图像数据格式  ffmpeg里面格式为26
     * @param var5 linesize 图像每行的占用byte，一般等于宽*像素字节大小，不用处理
     * @return 返回0
     */
    public  int OnRecvRGBAByte(byte[] var1, int var2, int var3, int var4, int var5)
    {

        Log.i("tiwolf", "RGB流返回: 字节流宽度-"+var2+";高度-"+var3+";数据格式-"+var4+";行宽-"+var5 );

        return 0;
    }


    /**
     * NV21图像数据流回调
     * 注意，不能在此回调函数中调用耗时的操作，否则会影响收流
     * @param nv21 nv21数据
     * @param w NV21图像的宽
     * @param h NV21图像的高
     * @param format NV21的图像数据格式  ffmpeg里面格式为24
     * @param linesize 图像每行的占用数字，一般等于宽，不用处理
     * @return 返回0
     */
    public  int OnRecvNv21Byte(byte[] nv21,int w, int h,int format,int linesize)
    {

        Log.i("tiwolf", "NV21流返回: 字节流宽度-"+w+";高度-"+h+";数据格式-"+format+";行宽-"+linesize );

        return 0;
    }




    public static final String TEST_URL = "rtmp://8.129.185.215:1935/live/0demo01";
    public static final String TEST_URL1 = "rtmp://192.168.1.118:1935/live/0demo01";

    private ConcurrentLinkedDeque<byte[]> mMidIntBufferCache=new ConcurrentLinkedDeque<>();
    private Thread mWorker;
    private final Object writeLock1=new Object();
    int num=0;

    /**
     * 将字节流转换成文件
     * TODO 2020.7.11 将yuv保存成文件
     *
     * @throws Exception
     */
    public void saveFile()throws Exception{

        mWorker=new Thread(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "run11111: "+mWorker.getName() );

                while (!Thread.interrupted()){
                    while (!mMidIntBufferCache.isEmpty()){
                        byte[] midBuffer=mMidIntBufferCache.poll();
                        num++;
                        File file=new File(Environment.getExternalStorageDirectory().getPath()+"/xin/intefly"+num+".jpg");

                        if(midBuffer != null && file!=null){
                            FileOutputStream fos = null;
                            try {
                                fos = new FileOutputStream(file);
                                fos.write(midBuffer,0,midBuffer.length);
                                fos.flush();
                            } catch (FileNotFoundException e) {
                                e.printStackTrace();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }finally {
                                try {
                                    fos.close();
                                    fos=null;
                                    file=null;
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }

//                        try {
//                            fos.close();
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
                    }
                    //Waiting for next frame
                    synchronized (writeLock1){
                        try {
                            //isEmpty() may take some time,so we set timeout to detect next frame
                            writeLock1.wait(200);
                        } catch (InterruptedException e) {
//                        e.printStackTrace();
                            mWorker.interrupt();
                        }
                    }

                }



            }
        });
        mWorker.start();


    }

    int width=0;
    int height=0;
    private Thread picWorker;
    private final Object writeLock = new Object();
    private ConcurrentLinkedDeque<byte[]> cacheLinkedDeque=new ConcurrentLinkedDeque<>();

    public void doPicWork(){
        Log.i(TAG, "doPicWork: 启动nv21数据处理" );
        picWorker=new Thread(new Runnable() {
            @Override
            public void run() {

                while (!Thread.interrupted()) {
                    while (!cacheLinkedDeque.isEmpty()) {
//                        Log.i(TAG, "run: 处理nv21数据" );
                        byte[] bytes=cacheLinkedDeque.poll();
                        if (bytes.length>0 && width>0 && height>0){
                            num++;
//                            Log.i(TAG, "run: 处理nv21图片==================="+bytes.length +";当前序列号："+num);
                            iShowPicture.showData(bytes,height,width);

//                            try {
//                                if (num>=100){
//                                    saveToSDCard(bytes,fei+num+".jpg");
//                                    num=0;
//
//                                }
//
//                            } catch (IOException e) {
//                                e.printStackTrace();
//                            }
                        }

                    }
                    // Waiting for next frame
                    synchronized (writeLock) {
                        try {
                            // isEmpty() may take some time, so we set timeout to detect next frame
                            writeLock.wait(500);
                        } catch (InterruptedException ie) {
                            picWorker.interrupt();
                        }
                    }
                }
            }
        });
        picWorker.start();
    }

    File file=null;
    OutputStream outputStream=null;
    boolean h264flag=true;
    //得到一个h264文件
    private void writeH264(byte[] data){
        if (onedo){
            onedo=false;
            Log.i(TAG, "帧数据 writeH264-111: "+Environment.getExternalStorageDirectory().getPath()+"/xin/intefly.h264");
            file=new File(Environment.getExternalStorageDirectory().getPath()+"/xin/intefly.h264");
            try {
                outputStream=new FileOutputStream(file);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(90*1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    h264flag=false;
                }
            }).start();
        }else {
            if (h264flag){
                try {
                    outputStream.write(data);
                    outputStream.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }else{
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }


    private File saveToSDCard(byte[] data,String filename) throws IOException {

//        String filename="intefly.jpg";

        File fileFolder = new File(Environment.getExternalStorageDirectory() + File.separator+"xin/");

        File jpgFile = new File(fileFolder, filename);
        FileOutputStream outputStream = new FileOutputStream(jpgFile);
        outputStream.write(data);
        outputStream.close();
        return jpgFile;
    }

    /**
     * 这个主要是获取从C++返回的数据，这个方法在C++里面已经写了。一定要public
     * @param log
     */
    public void showLog(String log){
        //再将参数传到具体使用参数上
        iShowPicture.showLog(log);
    }

    IShowPicture iShowPicture;
    public void showBitmap(IShowPicture showPicture){
        this.iShowPicture=showPicture;
        //1将当前类传过去
//        SetLogCallback(this);
    }

    @Override
    public void showpcm(byte[] pcm, int length) {
        long time=System.currentTimeMillis();
//                Log.i(TAG, "showpcm: 声音摄像头音频时间戳为"+time );
//        Log.i(TAG, "showpcm: 声音摄像头音频长度为"+length );
        if (isItfRtmpInitFlag>=0 && length>0){
            MaiteOpenGLView.SendAudioFrame(isItfRtmpInitFlag,length,pcm,time,0);
        }

    }

    @Override
    public void errorAudio() {
        restartAudio();
    }

    public void restartAudio(){
        if (aaCproduct!=null){
            Log.i(TAG, "ai restartAudio:先停止之前的音频++++++++++++++" );
            aaCproduct.stopAudioRecord();
            aaCproduct=null;
        }
        Log.i(TAG, "ai restartAudio: 重新开始音频录制获取+++++++++++++");
        aaCproduct=new AACproduct(this);
        aaCproduct.start();
    }

    /**
     * 开始推流历史视频
     * @param path 视频的绝对地址
     * @return
     */
    public int startPlayBack(String path,String room){
        Log.i(TAG, "startPlayBack 历史视频播放 文件名："+path+";目的url:"+TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01" );
        playBackHandler= MaiteOpenGLView.StartPlayback(path,TestConfig.RTMP_HEAR+ TestConfig.MEDIASV+TestConfig.RTMP_PARAMS+ FlyUtil.getSn(context)+"01"+"-"+room);
        return playBackHandler;
    }

    public int stopPlayBack(String path,int handle){
        return MaiteOpenGLView.StopPlayback(handle,path);
    }

    /**
     * 七牛云开始推流历史视频
     * @param path 视频的绝对地址
     * @return
     */
    public int startQiPlayBack(String path,String url){
        Log.i(TAG, "startPlayBack 历史视频播放 文件名："+path+";目的url:"+url );
        playBackHandler= MaiteOpenGLView.StartPlayback(path,url);
        return playBackHandler;
    }

    public int stopQiPlayBack(String path,int handle){
        return MaiteOpenGLView.StopPlayback(handle,path);
    }


    public int isEnd(int handle){
        return MaiteOpenGLView.IsStop(handle);
    }


    public interface IShowPicture{
        //        void show(Bitmap bitmap);
        void showData(byte[] data, int height, int width);

        void cameraIsWorking();

        void isCameraLink(long flag);

        void showLog(String log);

        void picIsMove();
    }
}
